package com.kpi.processflow.process.reader;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.kpi.processflow.process.Process;
import com.kpi.processflow.process.registry.ProcessDefinitionRegistry;
import com.kpi.processflow.util.JsonUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * @author Kevin Liu
 * @date 2020/5/3 9:25 下午
 */
@Slf4j
@Data
@Component
public class FileSystemProcessDefinitionReader implements ProcessDefinitionReader {

    private static final TypeReference<List<Process>> LIST_OF_PROCESS = new TypeReference<List<Process>>() {
    };

    public static final String DEFAULT_PROCESS_FILE_PATH = "PROCESS-FLOW/process_flow_*.json";

    private final ResourcePatternResolver fileResolver = new PathMatchingResourcePatternResolver();

    private Set<Process> definedProcesses;

    protected List<Process> loadProcessConfig(String resourcePath) throws Exception {
        List<Process> processes = Lists.newArrayList();
        Resource[] resources = this.fileResolver.getResources("classpath*:" + resourcePath);
        for (Resource r : resources) {
            processes.addAll(JsonUtils.deserializeList(r.getInputStream(), LIST_OF_PROCESS));
        }

        return processes;
    }

    @Override
    public Collection<Process> loadProcessDefinition() {
        if (!CollectionUtils.isEmpty(this.definedProcesses)) {
            return this.definedProcesses;
        } else {
            try {
                List<Process> defaultProcess = this.loadProcessConfig("PROCESS-FLOW/process_flow_*.json");
                Set<Process> all = Sets.newHashSet(defaultProcess);
                this.definedProcesses = Collections.unmodifiableSet(all);
                return this.definedProcesses;
            } catch (Exception e) {
                throw new RuntimeException("load process config fail");
            }
        }
    }
}
